package com.itstyle.seckill.topic.guava;

import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Auther: liuwenxiang
 * @Date: 2020/4/3 13:15
 * @Description:
 * 总结：
 * 1.消息总线的运行机制：
 *      发布方post事件到总线，订阅方在总线上register监听者，通过监听者模式消费消息
 * 2.消息总线类型：
 *      分为"同步"，"异步"两种类型，同步就是发布一个订阅一个，顺序着执行；异步就是发布方一直发布，订阅方按自己速度消费
 *      同步：发布订阅在同一个线程中执行
 *      异步：发布订阅不在同一个线程中执行，消费方会在线程池中得到一个线程执行。
 *
 * 3.消息特点：
 *      一个"事件"只能被一个订阅方订阅一次；可以被多个订阅者同时订阅，谁先注册到EventBus的，谁先执行。
 *
 *
 */
public class EventBusUtil {

    private static EventBus eventBus;

    private static AsyncEventBus asyncEventBus;

    private static ExecutorService executorService =new ThreadPoolExecutor(10,10,30, TimeUnit.SECONDS,new LinkedBlockingQueue<>());

    //采用"双重锁"方式创建一个单例对象
    public static EventBus getEventBus(){
        if(eventBus==null){//
            synchronized (EventBus.class){
                if(eventBus==null){
                    eventBus=new EventBus();
                }
            }
        }
        return eventBus;
    }

    public static AsyncEventBus getAsyncEventBus(){
        if(asyncEventBus==null){
            synchronized (AsyncEventBus.class){
                if(asyncEventBus==null){
                    asyncEventBus =new AsyncEventBus(executorService);
                }
            }
        }
        return  asyncEventBus;
    }

    public static void notasync(){
        //1.构建消息总线对象 2.注册监听器
        /**
         * 同步：发布一个事件，消费了之后，才会发布下一个事件，会影响发布速度，这个影响是因为消费完了才能发布下一条。
         */
        getEventBus().register(new EventListen2());
        /**
         * 异步："发布"和"订阅"隔离(各自运行,互补影响)，发布放可以一直发布，订阅方按着自己的速度去处理
         *  异步指的就是监听者，异步的方式拿一个线程去做订阅操作。
         */
        //3.注入消息
        for (int i=0;i<10;i++){
            CustomEvent customEvent = new CustomEvent(i);
            System.out.println("begin");
            getEventBus().post(customEvent);
            System.out.println("end");
        }

        try {
            System.out.println(new Date()+"我是主线程，我要休息10s================");
            TimeUnit.SECONDS.sleep(10);
            System.out.println(new Date()+"我是主线程，休息结束================");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        for (int i=5;i<15;i++){
            CustomEvent customEvent = new CustomEvent(i);
            getEventBus().post(customEvent);
        }
        System.out.println(new Date()+"我是主线程 end================");

    }


    public static void async(){
        //1.构建消息总线对象 2.注册监听器
        /**
         * 同步：发布一个事件，消费了之后，才会发布下一个事件，会影响发布速度，这个影响是因为消费完了才能发布下一条。
         */
        /**
         * 异步："发布"和"订阅"隔离(各自运行,互补影响)，发布放可以一直发布，订阅方按着自己的速度去处理
         *  异步指的就是监听者，异步的方式拿一个线程去做订阅操作。
         */
        getAsyncEventBus().register(new EventListen2());
        getAsyncEventBus().register(new EventListen1());
        //3.注入消息
        for (int i=0;i<10;i++){
            CustomEvent customEvent = new CustomEvent(i);
            System.out.println("begin"+i);
            getAsyncEventBus().post(customEvent);
            System.out.println("end");
        }

        try {
            System.out.println(new Date()+"我是主线程，我要休息10s================");
            TimeUnit.SECONDS.sleep(10);
            System.out.println(new Date()+"我是主线程，休息结束================");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        /*for (int i=5;i<15;i++){
            CustomEvent customEvent = new CustomEvent(i);
            getAsyncEventBus().post(customEvent);
        }*/
        System.out.println(new Date()+"我是主线程 end================");

    }
    public static void main(String[] args) {
        //同步
        //notasync();

        //异步
        async();


    }
}
